/*
 * Copyright (c) China Telecom Cloud Technology Co., Ltd. 2024-2025. All rights reserved.
 */
#include <iostream>
#include <cassert>
#include "Common.h"
#include "LruManager.h"

#include "Logger.h"

void LRUManager::init() {
    _lruQueue = std::list<SegMeta>();
    _lruMap   = std::unordered_map<SegmentId, 
                    std::list<SegMeta>::iterator>();
}



void LRUManager::insert(int64_t  segmentId, 
                        uint64_t offset, 
                        int32_t  idx) {
    auto it = _lruMap.find(segmentId);
    // 如果存在先删除
    if (it != _lruMap.end()) {
        _lruQueue.erase(it->second);
    }

    
    _lruQueue.push_back(SegMeta{segmentId, 
                                offset, 
                                idx
                            }
                    );
    auto queueIt = _lruQueue.end();
    queueIt--;
    _lruMap[segmentId] = queueIt;

    return;
}




void LRUManager::remove(int64_t segmentId) {
    auto &it = _lruMap[segmentId];

    _lruQueue.erase(it);
    _lruMap.erase(segmentId);
    return;
}


bool LRUManager::contain(int64_t segmentId) {
    return (_lruMap.find(segmentId) != _lruMap.end());
}


uint64_t LRUManager::getOffsetBySegmentId(int64_t segmentId) {
    return _lruMap[segmentId]->offset;
}


uint64_t LRUManager::getIdxBySegmentId(int64_t segmentId) {
    return _lruMap[segmentId]->idx;
}


// 重置特定的Segment到初始状态
void resetSegment(Segment &segment) {
    segment.setSegmentId(0);
    segment.setIsFilled(false);
    segment.setIsSaved(false);
    segment.setAccessTime(0);
    segment.setWriteInRecord(0);

    CacheInfo cacheInfo;
    cacheInfo.startLayer     = 0;
    cacheInfo.endLayer       = 0;
    cacheInfo.layerCacheSize = 0;
    cacheInfo.layerNum       = 0;
    segment.setCacheInfo(cacheInfo);

    BlockHashId blockHashId;
    segment.setBlockHashId(blockHashId);
    
    return;
}


// TODO(yangxianpku: 2025.08.18): 考虑环境变量控制
#define SEGMENT_TTL (1000000) // 单位us, 1s


void LRUManager::evict(std::vector<Segment> &segList, 
                    std::list<uint64_t> &freeList, 
                    int32_t proposeNum, 
                    int32_t &actualNum) {
    uint64_t curTime = getCurrentTimestampUs();

    actualNum = 0;
    for (auto it = _lruQueue.begin(); \
        actualNum < proposeNum && 
        it != _lruQueue.end();) {
        int32_t idx   = it->idx;
        auto& segment =  segList[idx];

        // 时间不够，而且没保存
        if (curTime - segment.getAccessTime() < SEGMENT_TTL 
            || !segment.getIsSaved()) {
            it++;
            continue;
        }
        
        LOG_WARN_FMT("evict segmentId: {}", segment.getSegmentId());
        freeList.push_back(it->offset);
        _lruMap.erase(segment.getSegmentId());
        _lruQueue.erase(it++);

        actualNum++;

        resetSegment(segment);
    }

    return;
}



void LRUManager::reorder(std::vector<SegmentId> &segmentIds) {
    for (int32_t i = segmentIds.size() - 1; i >= 0; i--) {
        if (_lruMap.find(segmentIds[i]) != _lruMap.end()) { // found
            auto &it = _lruMap[segmentIds[i]];              // iterator
            SegMeta obj = *it;

            _lruQueue.erase(it);
            _lruQueue.push_back(obj);
            auto queueIt = _lruQueue.end();
            queueIt--;
            _lruMap[segmentIds[i]] = queueIt;
        }
    }
    return;
}



std::vector<BlockHashId>  
LRUManager::getAllFilledSegmentIds(std::vector<Segment> &segList) {
    std::vector<BlockHashId> hashIds;
    LOG_DEBUG_FMT("lruQueue.size: {}", _lruQueue.size());

    for (auto it = _lruQueue.rbegin(); it != _lruQueue.rend(); it++) {
        int32_t idx = it->idx;
        auto& segment = segList[idx];
        LOG_DEBUG_FMT("hashId:{}", segment.getSegmentId());

        if (segment.getIsFilled()) {
            LOG_DEBUG_FMT("[Add Cache Info] hashId:{}, parent:{}, local:{}",
                        segment.getSegmentId(), 
                        segment.getParentHashId(), 
                        segment.getLocalHashId()
                    );

            hashIds.emplace_back(segment.getSegmentId(), 
                                segment.getParentHashId(), 
                                segment.getLocalHashId()
                            );
        }
    }
    return hashIds;
}


void LRUManager::print(std::vector<Segment> &segList) {
    int32_t index = 0;
    LOG_INFO_FMT("_lruMap size:{}, _lruQueue size:{}", 
                _lruMap.size(), 
                _lruQueue.size()
            );

    LOG_INFO_FMT("index\t\thashId\t\toffset\t\taccessTime");
    for (auto &obj : _lruQueue) {
        assert(obj.idx < segList.size());

        LOG_INFO_FMT("{}\t\t{}\t\t{}\t\t{}", index, obj.segmentId,
                    obj.offset, segList[obj.idx].getAccessTime());
        index++;
    }
}


void LRUManager::clean() {
    _lruQueue.clear();
    _lruMap.clear();
}